package com.cd2cd.code_template.configuration.authority;

import com.cd2cd.code_template.code_template.domain.SysAuth;
import com.cd2cd.code_template.code_template.mapper.SysAuthMapper;
import com.cd2cd.code_template.configuration.constants.DBConstants;
import com.cd2cd.code_template.curd.annotation.CustomCurdService;
import com.cd2cd.code_template.util.AppCtxHelper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.Title;
import java.lang.reflect.Method;
import java.util.*;


@Slf4j
@Component
public class AuthControlRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    private static Set<BeanDefinition> candidateComponents = new HashSet<>();

    @Resource
    private SysAuthMapper sysAuthMapper;

    @Override
    public void setEnvironment(Environment environment) {
          this.environment = environment;
    }


    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {

        // 筛选指定注解
        ClassPathScanningCandidateComponentProvider scan = new ClassPathScanningCandidateComponentProvider(false, this.environment);

        scan.addIncludeFilter(new AnnotationTypeFilter(AuthControl.class));

        String packageName = ClassUtils.getPackageName(annotationMetadata.getClassName());

        candidateComponents.addAll(scan.findCandidateComponents(packageName));

    }


    @SneakyThrows
    @PostConstruct
    private void insertOrUpdateAuth() {

        // 根据筛选的注解进行 权限控制
        for (BeanDefinition candidateComponent : candidateComponents) {

            // 反射获取注解类的方法属性
            String beanClassName = candidateComponent.getBeanClassName();
            Class<?> aClass = Class.forName(beanClassName);
            RequestMapping annotation = aClass.getAnnotation(RequestMapping.class);

            String classUrl = "";
            if (annotation != null) {
                String[] classUrls = annotation.value();
                classUrl = arrToString(classUrls);
            }

            AuthControl authControl = aClass.getAnnotation(AuthControl.class);

            String authName = authControl.name();
            String authType = authControl.type().name();
            String routePath = authControl.routePath();


            SysAuth sysAuthClass = new SysAuth();
            sysAuthClass.setGuid(aClass.getSimpleName());
            sysAuthClass.setAuthType(DBConstants.AuthType.MENU);
            sysAuthClass.setName(authName);
            sysAuthClass.setType(authType);
            sysAuthClass.setRoutePath(routePath);
            sysAuthClass.setAuth(DBConstants.BoolStr.YES);

            sysAuthMapper.insertOrUpdate(sysAuthClass);

            Method[] methods = aClass.getDeclaredMethods();

            for (Method method : methods) {
                String funAuthName = method.getName();
                String mode;
                String url ;

                RequestMapping requestMapping;
                GetMapping getMapping;
                PostMapping postMapping;
                PutMapping putMapping;
                DeleteMapping deleteMapping;
                PatchMapping patchMapping;

                if (null != (requestMapping = method.getAnnotation(RequestMapping.class))){
                    String[] value = requestMapping.value();
                    RequestMethod[] requestMethods = requestMapping.method();
                    mode = arrToString(requestMethods);
                    url = arrToString(value);
                }else if (null != (getMapping = method.getAnnotation(GetMapping.class))) {
                    String[] value = getMapping.value();
                    url = RequestMethod.GET.name();
                    mode = arrToString(value);
                }else if (null != (postMapping = method.getAnnotation(PostMapping.class))) {
                    String[] value = postMapping.value();
                    url = RequestMethod.POST.name();
                    mode = arrToString(value);
                }else if (null != (putMapping = method.getAnnotation(PutMapping.class))) {
                    String[] value = putMapping.value();
                    url = RequestMethod.PUT.name();
                    mode = arrToString(value);
                }else if (null != (deleteMapping = method.getAnnotation(DeleteMapping.class))) {
                    String[] value = deleteMapping.value();
                    url = RequestMethod.DELETE.name();
                    mode = arrToString(value);
                }else if (null != (patchMapping = method.getAnnotation(PatchMapping.class))) {
                    String[] value = patchMapping.value();
                    url = RequestMethod.PATCH.name();
                    mode = arrToString(value);
                }else continue;

                Title title = method.getAnnotation(Title.class);

                if (title != null) {
                    funAuthName = title.value();
                }

                // 判断是否以"/"开头 不是则加上
                if (!url.startsWith("/")) {
                    url = "/" + url;
                }

                url = classUrl + url;

                SysAuth sysAuthMethod = new SysAuth();

                sysAuthMethod.setType(authType);
                sysAuthMethod.setAuth(DBConstants.BoolStr.YES);
                sysAuthMethod.setName(funAuthName);
                sysAuthMethod.setAuthType(DBConstants.AuthType.AUTH);
                sysAuthMethod.setGuid(mode.toLowerCase() + "_" + url.replaceAll("/","_"));
                sysAuthMethod.setUrl(url);
                sysAuthMethod.setMode(mode);
                sysAuthMethod.setPid(sysAuthClass.getId());

                sysAuthMapper.insertOrUpdate(sysAuthMethod);
            }
        }

    }



    private String arrToString(Object[] arr) {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < arr.length; i++) {
            sb.append(arr[i].toString());
            if (i != (arr.length -1)) {
                sb.append(",");
            }
        }

        return sb.toString();
    }

}
